<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta content="width=device-width, initial-scale=1.0" name="viewport">

  <title>用户管理 -xx管理系统</title>

  <!-- Favicons -->
  <link href="assets/img/favicon.png" rel="icon">

  <!-- Vendor CSS Files -->
  <link href="assets/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
  <link href="assets/vendor/bootstrap-icons/bootstrap-icons.css" rel="stylesheet">
  <link href="assets/vendor/gridjs/dist/theme/mermaid.min.css" rel="stylesheet">

  <!-- Template Main CSS File -->
  <link href="assets/css/style.css" rel="stylesheet">
</head>

<body>

  <!-- ======= Header ======= -->
  <header id="header" class="header fixed-top d-flex align-items-center">

    <div class="d-flex align-items-center justify-content-between">
      <a href="index.html" class="logo d-flex align-items-center">
        <img src="assets/img/logo.png" alt="">
        <span class="d-none d-lg-block">XX管理系统</span>
      </a>
      <i class="bi bi-list toggle-sidebar-btn"></i>
    </div><!-- End Logo -->

    <nav class="header-nav ms-auto">
      <ul class="d-flex align-items-center">
        <li class="nav-item dropdown pe-3">

          <a class="nav-link nav-profile d-flex align-items-center pe-0" href="#" data-bs-toggle="dropdown">
            <img src="assets/img/profile-img.jpg" alt="Profile" class="rounded-circle">
            <span class="d-none d-md-block dropdown-toggle ps-2">用户名</span>
          </a><!-- End Profile Iamge Icon -->

          <ul class="dropdown-menu dropdown-menu-end dropdown-menu-arrow profile">
            <li class="dropdown-header">
              <h6>部门名</h6>
              <span>角色名</span>
            </li>
            <li>
              <hr class="dropdown-divider">
            </li>
            <li>
              <a class="dropdown-item d-flex align-items-center" href="personal.html">
                <i class="bi bi-gear"></i>
                <span>个人信息</span>
              </a>
            </li>
            <li>
              <hr class="dropdown-divider">
            </li>
            <li>
              <a class="dropdown-item d-flex align-items-center" href="#">
                <i class="bi bi-box-arrow-right"></i>
                <span>注销登录</span>
              </a>
            </li>

          </ul><!-- End Profile Dropdown Items -->
        </li><!-- End Profile Nav -->

      </ul>
    </nav><!-- End Icons Navigation -->

  </header><!-- End Header -->

  <!-- ======= Sidebar ======= -->
  <aside id="sidebar" class="sidebar">

    <ul class="sidebar-nav" id="sidebar-nav">

      <li class="nav-item">
        <a class="nav-link collapsed" href="index.html">
          <i class="bi bi-grid"></i>
          <span>个人主页</span>
        </a>
      </li><!-- End Dashboard Nav -->

      <li class="nav-item">
        <a class="nav-link " data-bs-target="#components-nav" data-bs-toggle="collapse" href="#">
          <i class="bi bi-menu-button-wide"></i><span>系统管理</span><i class="bi bi-chevron-down ms-auto"></i>
        </a>
        <ul id="components-nav" class="nav-content" data-bs-parent="#sidebar-nav">
          <li>
            <a href="system-user.html" class="active">
              <i class="bi bi-circle"></i><span>用户管理</span>
            </a>
          </li>
          <li>
            <a href="system-dept.html">
              <i class="bi bi-circle"></i><span>部门管理</span>
            </a>
          </li>
          <li>
            <a href="system-role.html">
              <i class="bi bi-circle"></i><span>角色管理</span>
            </a>
          </li>
        </ul>
      </li><!-- End Components Nav -->

      <li class="nav-item">
        <a class="nav-link collapsed" href="blank.html">
          <i class="bi bi-file-earmark"></i>
          <span>空白模板页</span>
        </a>
      </li><!-- End Blank Page Nav -->

    </ul>

  </aside><!-- End Sidebar-->

  <main id="main" class="main">
    <div class="pagetitle">
      <nav>
        <ol class="breadcrumb">
          <li class="breadcrumb-item"><a href="index.html">主页</a></li>
          <li class="breadcrumb-item">系统管理</li>
          <li class="breadcrumb-item active">用户管理</li>
        </ol>
      </nav>
    </div><!-- End Page Title -->

    <section class="section">
      <div class="row">
        <div class="col-lg-12">
          <div class="card">
            <div class="card-body">
              <h5 class="card-title">用户列表</h5>
              <!--查询表单-->
              <form id="searchForm" class="row row-cols-lg-auto g-3 mb-3 align-items-center">
                <div class="col-12">
                  <div class="input-group">
                    <input type="text" class="form-control" name="username" placeholder="账号" />
                  </div>
                </div>
                <div class="col-12">
                  <div class="input-group">
                    <input type="text" class="form-control" name="name" placeholder="姓名" />
                  </div>
                </div>
                <div class="col-12">
                  <div class="input-group">
                    <input type="text" class="form-control" name="phone" placeholder="联系电话" />
                  </div>
                </div>
                <div class="col-12">
                  <select class="form-select" name="enableState">
                    <option selected value="">状态</option>
                    <option value="启用">启用</option>
                    <option value="停用">停用</option>
                  </select>
                </div>
                <div class="col-12">
                  <button type="submit" class="btn btn-primary"><i class="bi bi-search"></i>查询</button>
                  <button type="reset" class="btn btn-secondary"><i class="bi bi-arrow-repeat"></i>重置</button>
                  <button id="createUserButton" type="button" class="btn btn-success"><i
                      class="bi bi-plus"></i>添加</button>
                </div>
              </form>
              <!-- 数据表格-->
              <div id="dataTable"></div>
            </div>
          </div>
        </div>
      </div>
    </section>

  </main><!-- End #main -->

  <!-- ======= Footer ======= -->
  <footer id="footer" class="footer">
    <div class="credits">
      Designed by 2022030202033-曾广生
    </div>
  </footer><!-- End Footer -->
  <!--操作成功信息提醒 Start-->
  <div class="toast-container position-absolute top-0 end-0">
    <div id="successToastEl" class="toast hide" role="alert" aria-live="assertive" aria-atomic="true"
      style="color: #fff;background-color: #19875488;">
      <div class="toast-body"><i class="bi bi-check-circle"></i><span id="successMessage">successMessage</span></div>
    </div>
  </div>
  <!--操作成功信息提醒 End-->
  <!--重置密码模态框 start-->
  <div class="modal fade" id="resetPwdModalEl" tabindex="-1">
    <form id="resetPwdForm" class="needs-validation" novalidate>
      <div class="modal-dialog modal-dialog-centered modal-lg">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">重置密码</h5>
            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-today">
            <div class="px-5">
              <div id="resetPwdAlert"></div>
              <div class="row mb-3">
                <label for="password" class="col-sm-3 col-form-label d-flex justify-content-end">请输入新密码：</label>
                <div class="col-sm-9">
                  <input type="password" class="form-control" id="password" name="password" required />
                </div>
              </div>
              <div class="row mb-3">
                <label for="passwordRepeat" class="col-sm-3 col-form-label d-flex justify-content-end">再次输入密码：</label>
                <div class="col-sm-9">
                  <input type="password" class="form-control" id="passwordRepeat" name="passwordRepeat" required />
                </div>
              </div>
            </div>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" name="close" data-bs-dismiss="modal">关闭</button>
            <button type="submit" class="btn btn-primary">提交</button>
          </div>
        </div>
      </div>
    </form>
  </div>
  <!--重置密码模态框 end-->
  <!--编辑用户模态框 Start-->
  <div class="modal fade" id="editUserModalEl" aria-labelledby="editUserModal" tabindex="-1" aria-hidden="true">
    <form id="editUserForm" class="needs-validation" novalidate>
      <div class="modal-dialog modal-dialog-centered modal-lg">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">编辑用户</h5>
            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body">
            <div class="px-5">
              <div id="editUserAlert"></div>
              <div class="row mb-3">
                <label for="username" class="col-sm-2 col-form-label d-flex justify-content-end">账号/用户名</label>
                <div class="col-sm-10">
                  <input type="text" class="form-control" id="username" name="username" required />
                </div>
              </div>
              <div class="row mb-3">
                <label for="name" class="col-sm-2 col-form-label d-flex justify-content-end">姓名</label>
                <div class="col-sm-10">
                  <input type="text" class="form-control" id="name" name="name" required />
                </div>
              </div>
              <div class="row mb-3">
                <label for="phone" class="col-sm-2 col-form-label d-flex">手机号码</label>
                <div class="col-sm-10">
                  <input type="text" class="form-control" id="phone" name="phone" />
                </div>
              </div>
              <div class="row mb-3">
                <label for="email" class="col-sm-2 col-form-label d-flex">邮箱</label>
                <div class="col-sm-10">
                  <input type="email" class="form-control" id="email" name="email" />
                </div>
              </div>
              <div class="row mb-3">
                <legend class="col-sm-2 col-form-label d-flex justify-content-end">部门</legend>
                <div class="col-sm-10">
                  <select name="deptId" class="form-select" aria-label="select dept" required></select>
                </div>
              </div>
              <div class="row mb-3">
                <legend class="col-sm-2 col-form-label d-flex justify-content-end">角色</legend>
                <div class="col-sm-10">
                  <select name="roleId" class="form-select" aria-label="select role" required></select>
                </div>
              </div>
              <div class="row mb-3">
                <label for="fileInput" class="col-sm-2 col-form-label d-flex justify-content-end">头像</label>
                <div class="col-sm-10">
                  <input type="hidden" class="form-control" name="avatar" />
                  <input type="file" id="avatarFileInput" style="display: none;" accept=".jpg,.jpeg,.png" />
                  <img id="userAvatarImg" src="assets/img/user.png" height="120px" />
                  <div class="pt-2">
                    <a id="uploadAvatarButton" class="btn btn-primary btn-sm" title="上传新的头像">
                      <i class="bi bi-upload"></i>
                    </a>
                    <a id="removeAvatarButton" class="btn btn-danger btn-sm" title="删除用户头像">
                      <i class="bi bi-trash"></i>
                    </a>
                  </div>
                  <div id="uploadAvatarAlert" class="mt-3"></div>
                </div>
              </div>
            </div>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" name="close" data-bs-dismiss="modal">关闭</button>
            <button type="submit" class="btn btn-primary">提交</button>
          </div>
        </div>
      </div>
    </form>
  </div>
  <!--编辑用户模态框 End-->
  <!--密码框 Start-->
  <div id="passwordInput" class="row mb-3 d-none">
    <label for="passwordEdit" class="col-sm-2 col-form-label d-flex justify-content-end">密码</label>
    <div class="col-sm-10">
      <input type="password" class="form-control" id="passwordEdit" name="password" required />
    </div>
  </div>
  <!--密码框 End-->
  <!--禁用|启用用户信息确认框 Start-->
  <div class="toast_container position-fixed top-50 start-50">
    <div id="toggleUserToastEl" class="toast hide" role="alert" aria-live="assertive" aria-atomic="true">
      <div class="toast-body">
        <span id="toggleUserMessage"></span>
        <div class="mt-2 pt-2 border-top">
          <button id="comfirmToggleUser" type="button" class="btn btn-primary btn-sm">确认</button>
          <button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="toast">取消</button>
        </div>
      </div>
    </div>
  </div>
  <!--禁用|启用用户信息确认框 End-->
  <a href="#" class="back-to-top d-flex align-items-center justify-content-center"><i
      class="bi bi-arrow-up-short"></i></a>

  <!-- Vendor JS Files -->
  <script src="assets/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
  <script src="assets/vendor/gridjs/dist/gridjs.umd.js"></script>
  <script src="assets/vendor/gridjs/I10n/dist/l10n.umd.js"></script>
  <script src="assets/vendor/moment/moment.js"></script>
  <!-- Template Main JS File -->
  <script src="assets/js/main.js"></script>
  <!--页面JS代码-->
  <script>
    //定义接口地址url
    const url = "/api/rest/user";
    //定义数据users，存放查询返回的用户数据
    let users = [];
    //表格配置：列定义
    const columns = [
      {
        id: "id",
        hidden: true,
      },
      {
        id: "username",
        name: "用户名",
      },
      {
        id: "enableState",
        name: "状态",
      },
      {
        id: "name",
        name: "姓名",
      },
      {
        id: "phone",
        name: "手机",
      },
      {
        id: "email",
        name: "邮箱",
      },
      {
        id: "createAt",
        name: "创建时间",
      },
      {
        name: "操作",
        name: "操作",
        width: "25%",
        formatter: (_, row) => {
          const enableState = row.cells[2].data; // 获取状态
          return gridjs.html(`
              <button id="updateUserButton" type="button" class="btn btn-sm btn-primary m-1">
                  <i class="bi bi-pencil-square"></i>编辑
              </button>

              <button id="resetPwdButton" type="button" class="btn btn-sm btn-warning m-1">
                  <i class="bi bi-credit-card"></i>重置密码
              </button>
              
              <button id="${enableState === '启用' ? 'disable' : 'enable'}" type="button" class="btn btn-sm btn-${enableState === '启用' ? 'danger' : 'success'} m-1">
                 <i class="bi bi-${enableState === '启用' ? 'slash-circle' : 'circle'}"></i>${enableState === '启用' ? '禁用' : '启用'}
              </button>
            
          `);
        }


      },
    ];
    //表格配置：服务器请求响应处理
    const server = {
      url,
      then: (data) => {
        users = data.content;
        return data.content.map((item) => [
          item.id,
          item.username,
          item.enableState,
          item.name,
          item.phone,
          item.email,
          item.updateAt ? moment(item.updateAt).format("YYYY-MM-DD hh:mm:ss") : "",
        ]);
      },
      total: (data) => data.totalElements,
    };
    //表格配置：分页处理
    const pagination = {
      limit: 10,
      server: {
        url: (prev, page, limit) => addQueryParam(prev, `size=${limit}&page=${page}`),
      },
    };
    //grid表格配置
    const options = {
      columns,
      server,
      pagination,
      language: gridjs.l10n.cnCN,
    };

    //页面加载完成后执行
    window.onload = function () {
      //创建grid表格
      const grid = new gridjs.Grid(options);
      //渲染DOM
      grid.render(dataTable);
      const successToastEl = document.getElementById("successToastEl");
      const successToast = new bootstrap.Toast(successToastEl, { autohide: true, delay: 2000 });
      //定义变量userId
      let userId = null;
      //监听表格点击事件
      grid.on("cellClick", (...args) => {
        const event = args[0];
        userId = args[3].cells[0].data;
        if (event.target?.id === "resetPwdButton") {
          resetPwdForm.id.value = userId;
          resetPwdModal.show();
          return;
        }
        //如果点击“编辑”按钮
        if (event.target?.id === "updateUserButton") {
          //查找获取该行用户数据
          const user = users.find((user) => user.id === userId);
          //将用户数据填写到“编辑用户表单”中
          editUserForm.avatar.value = user.avatar;
          editUserForm.username.value = user.username;
          editUserForm.name.value = user.name;
          editUserForm.phone.value = user.phone;
          editUserForm.email.value = user.email;
          editUserForm.deptId.value = user.dept.id;
          editUserForm.roleId.value = user.role.id;
          if (user.avatar) {
            userAvatarImg.src = `/api/rest/attachment/${user.avatar}`;
          } else {
            userAvatarImg.src = `assets/img/user.png`;
          }
          //显示“编辑用户”模态框
          editUserModal.show();
          return;
        }

        // 如果点击“禁用”按钮
        if (event.target?.id === "disable") {
          toggleUserMessage.innerText = "确定要禁用该用户吗？";
          toggleUserToastEl.classList.remove("hide");
          toggleUserToast.show();
          return;
        }

        // 如果点击“启用”按钮
        if (event.target?.id === "enable") {
          toggleUserMessage.innerText = "确定要启用该用户吗？";
          toggleUserToastEl.classList.remove("hide");
          toggleUserToast.show();
          return;
        }

      }
      )
      //注册查询表单按钮的事件监听
      searchForm.addEventListener("submit", (event) => {
        //创建successToast
        event.preventDefault();
        const formData = new FormData();
        formData.set("username", searchForm.username.value.trim());
        formData.set("name", searchForm.name.value.trim());
        formData.set("phone", searchForm.phone.value.trim());
        formData.set("enableState", searchForm.enableState.value);
        //创建 URLSearchParams 对象
        const searchParams = new URLSearchParams(formData);
        //将表单参数添加到url中
        options.server.url = addQueryParam(url, searchParams.toString());
        //刷新表格
        grid.updateConfig(options).forceRender();
        successToast.show();
      });
      //创建“修改用户密码”模态框
      const resetPwdModalEl = document.getElementById("resetPwdModalEl");
      const resetPwdModal = new bootstrap.Modal(resetPwdModalEl, { keyboard: false });
      //注册事件监听
      resetPwdModalEl.addEventListener("hidden.bs.modal", (event) => {
        //重置表单
        resetPwdForm.reset();
        resetPwdForm.classList.remove("was-validated");
        //清除警告框
        resetPwdAlert.innerHTML = "";
      });
      //重置密码表单提交事件处理
      resetPwdForm.addEventListener("submit", (event) => {
        event.preventDefault();
        if (resetPwdForm.checkValidity()) {
          const formData = Object.fromEntries(new FormData(resetPwdForm));
          fetch(`${url}/${userId}/update-password`, {
            method: "PATCH",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(formData),
          }).then((response) => {
            if (response.ok) {
              resetPwdModal.hide();
              successMessage.innerText = "重置密码成功！";
              successToast.show();
              grid.updateConfig(options).forceRender();
            } else {
              response.json().then((error) => {
                createAlert(resetPwdAlert, error.message, "danger");
              });
            }
          });
        } else {
          resetForm.classList.add("was-validated");
        }
      });
      //创建“编辑用户模态框”
      const editUserModalEl = document.getElementById("editUserModalEl");
      const editUserModal = new bootstrap.Modal(editUserModalEl, { keyboard: false });
      //注册事件监听
      editUserModalEl.addEventListener("hidden.bs.modal", (event) => {
        //重置表单
        editUserForm.reset();
        editUserForm.classList.remove("was-validated");
        //清除警告框
        editUserAlert.innerHTML = "";
        //删除密码框
        const passwordClone = editUserForm.querySelector("#passwordClone");
        if (passwordClone) {
          passwordClone.remove();
        }
      });
      //获取部门信息
      fetch("/api/rest/dept/all")
        .then((response) => response.json())
        .then((data) => {
          const selectElement = editUserForm.querySelector('[name="deptId"]');
          data.forEach((item) => {
            const option = document.createElement("option");
            option.value = item.id;
            option.innerText = item.name;
            selectElement.appendChild(option);
          });
        })
        .catch((error) => {
          console.error("Error:", error);
        });
      //获取角色信息
      fetch("/api/rest/role/all")
        .then((response) => response.json())
        .then((data) => {
          let selectElement = editUserForm.querySelector('[name="roleId"]');
          data.forEach((item) => {
            let option = document.createElement("option");
            option.value = item.id;
            option.innerText = item.name;
            selectElement.appendChild(option);
          });
        })
        .catch((error) => {
          console.error("Error:", error);
        });
      //注册“编辑用户表单”中的“删除用户头像按钮”的事件监听
      removeAvatarButton.addEventListener("click", (event) => {
        editUserForm.avatar.value = null;
        userAvatarImg.src = "assets/img/user.png";
      });
      //注册“编辑用户表单”中的“上传用户头像按钮”的事件监听
      uploadAvatarButton.addEventListener("click", (event) => {
        avatarFileInput.click();
      });
      //注册“编辑用户表单”中的隐藏表单控件“文件上传”的事件监听
      avatarFileInput.addEventListener("change", (event) => {
        const files = event.target.files;
        if (files.length > 0) {
          const file = files[0];
          const allowTypes = ["image/jpeg", "image/png"];
          if (!allowTypes.includes(file.type)) {
            createAlert(uploadAvatarAlert, "请上传jpg或png格式的图片", "danger");
            return;
          }
          const maxSize = 1 * 1024 * 1024;
          if (file.size > maxSize) {
            createAlert(uploadAvatarAlert, "文件太大,请上传小于1M的图片", "danger");
            return;
          }
          //清除警告框
          uploadAvatarAlert.innerHTML = "";
          //构建附件上传表单数据
          const formData = new FormData();
          formData.append("file", file);
          formData.append("type", "头像");
          fetch("/api/rest/attachment", {
            method: "POST",
            body: formData,
          })
            .then((response) => response.json())
            .then((attachment) => {
              userAvatarImg.src = attachment.url;
              editUserForm.avatar.value = attachment.id;
            })
            .catch((error) => {
              createAlert(uploadAvatarAlert, error.message, "danger");
            });
        }
      });
      //编辑用户表单提交事件处理
      editUserForm.addEventListener("submit", (event) => {
        event.preventDefault();
        if (editUserForm.checkValidity()) {
          //获取表单参数
          const formData = Object.fromEntries(new FormData(editUserForm));
          //根据userId值判断是更新用户 还是 新建用户
          let editUrl = userId ? `${url}/${userId}` : url;
          let editMethod = userId ? "PATCH" : "POST";
          fetch(editUrl, {
            method: editMethod,
            headers: {
              "Content-Type": "application/json",
            },
            body: JSON.stringify(formData),
          }).then((response) => {
            if (response.ok) {
              editUserModal.hide();
              successMessage.innerText = userId ? "更新用户信息成功！" : "创建用户成功！";
              successToast.show();
              grid.updateConfig(options).forceRender();
            } else {
              response.json().then((error) => {
                createAlert(editUserAlert, error.message, "danger");
              });
            }
          });
        } else {
          editUserForm.classList.add("was-validated");
        }
      });
      //注册“添加用户”按钮的事件监听
      createUserButton.addEventListener("click", (event) => {
        //克隆密码框
        const passwordClone = passwordInput.cloneNode(true);
        passwordClone.id = "passwordClone";
        passwordClone.classList.remove("d-none");
        editUserForm.querySelectorAll("div.row.mb-3")[1].after(passwordClone);
        userAvatarImg.src = `assets/img/user.png`;
        editUserModal.show();
      });
      //创建“禁用|启用”消息框
      const toggleUserToastEl = document.getElementById("toggleUserToastEl");
      const toggleUserToast = new bootstrap.Toast(toggleUserToastEl, { autohide: false });
      //创建点击“切换状态”按钮事件监听
      comfirmToggleUser.addEventListener("click", (event) => {
        if (userId) {
          fetch(`${url}/${userId}/toggle`, { method: "PATCH" }).then((response) => {
            if (response.ok) {
              toggleUserToast.hide();
              successMessage.innerText = "切换用户状态成功！";
              successToast.show();
              grid.updateConfig(options).forceRender();
            }
          });
        }
      });

    }; 
  </script>
</body>

</html>